/*
 *  Licensed to the Apache Soimport static junit.framework.Assert.fail;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.Id;
import javax.persistence.LockModeType;
import javax.persistence.Query;
able law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package fr.loof.fonzie.gigai;

import static junit.framework.Assert.fail;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.Id;
import javax.persistence.LockModeType;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Query;

import org.springframework.core.annotation.AnnotationUtils;

/**
 * @author ndeloof
 * @deprecated see InMemoryEntityManager
 */
@Deprecated
public class EntityManagerGigai
    implements EntityManager
{
    private Map<Class, Set> instances = new HashMap<Class, Set>();

    private long sequence = 990000;

    private Map<Object, List<String[]>> queries = new HashMap<Object, List<String[]>>();

    private Map<String, String> namedQueries = new HashMap<String, String>();

    public void register( Object entity, String... criterias )
    {
        readNamedQueries( entity );

        if ( getId( entity ) == null )
        {
            setId( sequence++, entity );
        }
        List<String[]> combinations = queries.get( entity );
        if ( combinations == null )
        {
            combinations = new LinkedList<String[]>();
            queries.put( entity, combinations );
        }
        combinations.add( criterias );
    }

    private void readNamedQueries( Object entity )
    {
        NamedQueries nqs = AnnotationUtils.findAnnotation( entity.getClass(), NamedQueries.class );
        if ( nqs != null )
        {
            for ( NamedQuery nq : nqs.value() )
            {
                namedQueries.put( nq.name(), nq.query() );
            }
        }
        NamedQuery nq = AnnotationUtils.findAnnotation( entity.getClass(), NamedQuery.class );
        if ( nq != null )
        {
            namedQueries.put( nq.name(), nq.query() );
        }
    }

    protected List findMatchingEntities( String query )
    {
        List result = new LinkedList();
        for ( Map.Entry<Object, List<String[]>> entry : queries.entrySet() )
        {
            String name = entry.getKey().getClass().getSimpleName();
            if ( !query.contains( "from " + name + " " ) )
            {
                continue;
            }

            List<String[]> combiantions = entry.getValue();
            for ( String[] criterias : combiantions )
            {
                boolean matches = true;
                for ( String criteria : criterias )
                {
                    if ( !query.contains( criteria ) )
                    {
                        matches = false;
                    }
                }
                if ( matches )
                {
                    result.add( entry.getKey() );
                    break;
                }
            }
        }
        return result;
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#clear()
     */
    public void clear()
    {
        instances.clear();
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#close()
     */
    public void close()
    {
        // Nop
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#contains(java.lang.Object)
     */
    public boolean contains( Object entity )
    {
        Object pk = getId( entity );
        for ( Object persistent : instances.get( entity.getClass() ) )
        {
            if ( pk.equals( getId( persistent ) ) )
            {
                return true;
            }
        }
        return false;
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#createNamedQuery(java.lang.String)
     */
    public Query createNamedQuery( String name )
    {
        return new QueryGigai( namedQueries.get( name ), this );
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#createNativeQuery(java.lang.String)
     */
    public Query createNativeQuery( String sqlString )
    {
        return new QueryGigai( sqlString, this );
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#createNativeQuery(java.lang.String, java.lang.Class)
     */
    public Query createNativeQuery( String sqlString, Class resultClass )
    {
        return new QueryGigai( sqlString, this );
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#createNativeQuery(java.lang.String, java.lang.String)
     */
    public Query createNativeQuery( String sqlString, String resultSetMapping )
    {
        return new QueryGigai( sqlString, this );
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#createQuery(java.lang.String)
     */
    public Query createQuery( String qlString )
    {
        return new QueryGigai( qlString, this );
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#find(java.lang.Class, java.lang.Object)
     */
    public <T> T find( Class<T> entityClass, Object primaryKey )
    {
        for ( Object persistent : instances.get( entityClass ) )
        {
            if ( primaryKey.equals( getId( persistent ) ) )
            {
                return (T) persistent;
            }
        }
        throw new EntityNotFoundException();
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#flush()
     */
    public void flush()
    {
        // Nop
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#getDelegate()
     */
    public Object getDelegate()
    {
        return null;
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#getFlushMode()
     */
    public FlushModeType getFlushMode()
    {
        return FlushModeType.AUTO;
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#getReference(java.lang.Class, java.lang.Object)
     */
    public <T> T getReference( Class<T> entityClass, Object primaryKey )
    {
        try
        {
            T entity = entityClass.newInstance();
            setId( primaryKey, entity );

            instances.get( entityClass ).add( entity );
            return entity;
        }
        catch ( Exception e )
        {
            fail( "Failed to create " + entityClass );
            return null;
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#getTransaction()
     */
    public EntityTransaction getTransaction()
    {
        return null;
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#isOpen()
     */
    public boolean isOpen()
    {
        return true;
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#joinTransaction()
     */
    public void joinTransaction()
    {
        // Nop
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#lock(java.lang.Object, javax.persistence.LockModeType)
     */
    public void lock( Object entity, LockModeType lockMode )
    {
        // Nop
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#merge(java.lang.Object)
     */
    public <T> T merge( T entity )
    {
        boolean persistent = instances.get( entity.getClass() ).contains( entity );
        if ( !persistent )
        {
            fail( "Try to merge entity" + entity + " that is not present in entitymanager" );
        }
        return entity;
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#persist(java.lang.Object)
     */
    public void persist( Object entity )
    {
        setId( entity, sequence++ );

        instances.get( entity.getClass() ).add( entity );
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#refresh(java.lang.Object)
     */
    public void refresh( Object entity )
    {
        boolean persistent = instances.get( entity.getClass() ).contains( entity );
        if ( !persistent )
        {
            fail( "Try to refresh entity" + entity + " that is not persistent" );
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#remove(java.lang.Object)
     */
    public void remove( Object entity )
    {
        if ( !instances.get( entity.getClass() ).remove( entity ) )
        {
            fail( "Try to remove entity" + entity + " that is not persistent" );
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see javax.persistence.EntityManager#setFlushMode(javax.persistence.FlushModeType)
     */
    public void setFlushMode( FlushModeType flushMode )
    {
        // Nop
    }

    protected <T> void setId( Object primaryKey, T entity )
    {
        Class clazz = entity.getClass();
        do
        {
            for ( Field field : clazz.getDeclaredFields() )
            {
                if ( field.getAnnotation( Id.class ) != null )
                {
                    field.setAccessible( true );
                    try
                    {
                        field.set( entity, primaryKey );
                        break;
                    }
                    catch ( Exception e )
                    {
                        fail( "Failed to set entity ID" );
                    }
                }
            }
        }
        while ( ( clazz = clazz.getSuperclass() ) != Object.class );
    }

    protected Object getId( Object entity )
    {
        Class clazz = entity.getClass();
        do
        {
            for ( Field field : clazz.getDeclaredFields() )
            {
                if ( field.getAnnotation( Id.class ) != null )
                {
                    field.setAccessible( true );
                    try
                    {
                        return field.get( entity );
                    }
                    catch ( Exception e )
                    {
                        fail( "Failed to read entity ID" );
                    }
                }
            }
        }
        while ( ( clazz = clazz.getSuperclass() ) != Object.class );
        fail( "Failed to retrieve entity ID" );
        return null;
    }

}
